
//#include "stdafx.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "CinematicThread.h"
#include "CinematicCommand.h"
#include "Cinematic.h"
#include "GameObjectManager.h"
#include "TutorialManager.h"
#include "game.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
CinematicThread::CinematicThread() : m_InstructionPointer(-1)
{	
	m_Name = "";	
	m_lastExecutedEvent = -1;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
CinematicThread::~CinematicThread()
{
	for (int i = 0 ; i < m_CinematicEvent.size() ; i++ )
	{
		array<CinematicCommand*>&	cmds = m_CinematicEvent[i]->m_CommandData;

		for (int j = 0 ; j < cmds.size() ; j++)
		{
			SAFE_DELETE(cmds[j]);
		}
		cmds.clear();	

		SCinematicEvent* s = m_CinematicEvent[i];

		SAFE_DELETE(s);
	}

	m_CinematicEvent.clear();
}

void CinematicThread::SaveData(CWriteFile* stream)
{
	for(int i=0;i<m_CinematicEvent.size();i++)
	{
		stream->WriteS32(m_CinematicEvent[i]->m_CurrentStep);
		stream->WriteF32(m_CinematicEvent[i]->m_Time);
//		array<CinematicCommand*>	m_CommandData; //bgbejan save/no save???
	}

	//stream->WriteGameObjPtr(m_Obj);
	//stream->WriteGameObjPtr(m_owner);

	stream->WriteS32(m_Id);	
	stream->WriteS32(m_Type);		
	stream->WriteS32(m_ObjId);
	stream->WriteS32(m_lastExecutedEvent);
	stream->WriteF32(m_currentTime);
	stream->WriteS32(m_InstructionPointer);
	stream->WriteU8 (m_isActive);
	stream->WriteU8 (m_hasFinalState);
	//stream->WriteU8 (m_bTestResult);
	//stream->WriteU8 (m_bIsTest);
}

void CinematicThread::LoadData(CReadFile* stream)
{
	for(int i=0;i<m_CinematicEvent.size();i++)
	{
		m_CinematicEvent[i]->m_CurrentStep = stream->ReadS32();
		m_CinematicEvent[i]->m_Time = stream->ReadF32();
//		array<CinematicCommand*>	m_CommandData; //bgbejan save/no save???
	}

	//m_Obj = stream->ReadGameObjPtr();
	//m_owner = (Cinematic *)stream->ReadGameObjPtr();

	m_Id = stream->ReadS32();
	m_Type = stream->ReadS32();
	m_ObjId = stream->ReadS32();
	m_lastExecutedEvent = stream->ReadS32();
	m_currentTime = stream->ReadF32();
	m_InstructionPointer = stream->ReadS32();
	m_isActive = stream->ReadU8();
	m_hasFinalState = stream->ReadU8();
	//m_bTestResult = stream->ReadU8();
	//m_bIsTest = stream->ReadU8();
}



GameObjectListInterface& CinematicThread::GetGameObjects()
{
	return GetGameObjectManager()->GetGameObjects();
	
}

//GameObjectListInterface& CinematicThread::GetGenericWPs()
//{
//	if(Game::Instance()->IsMenuWorldActive())
//	{
//		return *Game::Instance()->GetMenuWorld()->GetGenericWPs();
//	}
//	else
//	{
//		return Game::Instance()->m_world->GetGameObjectManager()->GetGenericWPsObjects();
//	}
//}

//GameObjectListInterface& CinematicThread::GetCinematicObjects()
//{
//	return GetGameObjectManager()->GetCinematicObjects();	
//}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
bool CinematicThread::Init( int id, Cinematic *owner )
{
	m_Id = id ;
	m_owner = owner;

	if (m_Type == E_THREAD_TYPE_OBJ)
	{
		if (m_ObjId == -1)
		{
			DEBUG_OUT("CCinematicThread::Init() Thread of type Object with no object Set !\n");
			return false;
		}

		m_Obj = GetGameObjects().FindObject(m_ObjId);

		if (!m_Obj)
		{
			//m_Obj = GetCinematicObjects().FindObject(m_ObjId);

			if (!m_Obj)
			{				
				DEBUG_OUT("CCinematicThread::Init() Thread of type Object with NULL object !\n");
				return false;
			}
		}
	}

	for (int i = 0 ; i < m_CinematicEvent.size() ; i++ )
	{
		m_CinematicEvent[i]->m_CurrentStep = 0;
	}

	m_hasFinalState = false;
	//m_isInCutscene = false;

	if (m_CinematicEvent.size() > 0  && m_CinematicEvent[m_CinematicEvent.size() - 1]->m_Time == FINAL_ACTION_TIME)
	{
		m_hasFinalState = true;
	}

	m_currentTime = 0;	
	m_lastExecutedEvent = -1;

	return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
bool CinematicThread::Update( float time )
{
	//EBUG_OUT("Update CinematicThread Id %d lastExecutedEvent %d time %.3f\n", m_Id, m_lastExecutedEvent, time);

	int eventsToParse = (m_hasFinalState?m_CinematicEvent.size() - 1:m_CinematicEvent.size());

	for (int i = m_lastExecutedEvent + 1 ; i < eventsToParse; i++ )
	{
//		DEBUG_OUT("CCinematicThread::Update Obj %d Cmd Time %.3f , Crt time %.3f , Updated %d  " , m_ObjId , m_CinematicEvent[i].m_Time , time , m_CinematicEvent[i].m_bUpdated );

		if (m_CinematicEvent[i]->m_Time <= m_currentTime)
		{
			if (!executeCommand(m_CinematicEvent[i]))
			{
				break;
			}

			bool bCompletedEvent = m_CinematicEvent[i]->m_CurrentStep >= m_CinematicEvent[i]->m_CommandData.size();

			if (!bCompletedEvent) 
			{
				m_currentTime = m_CinematicEvent[i]->m_Time;
				time = 0; //do not add time for this case
				break;
			}
			
			m_lastExecutedEvent = i;
			
		}
		else
		{
			break;
		}
	}

	m_currentTime += time;

	//DEBUG_OUT("-----------%d m_lastExecutedEvent=%d size=%d\n", m_lastExecutedEvent >= (s32)(m_CinematicEvent.size() - 1), m_lastExecutedEvent, m_CinematicEvent.size() - 1);
	return m_lastExecutedEvent >= (s32)(eventsToParse - 1);
}

void CinematicThread::doFinalAction ()
{
	if (m_hasFinalState)
	{
		int lastEvent = m_CinematicEvent.size() - 1;

		if (lastEvent >= 0)
		{
			executeCommand(m_CinematicEvent[lastEvent]);
		}
	}
}

void CinematicThread::reset ()
{	
	m_currentTime = 0;	
	m_lastExecutedEvent = -1;
	for(int i =0;i<m_CinematicEvent.size();i++)
		m_CinematicEvent[i]->m_CurrentStep = 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
bool CinematicThread::doCommand(CinematicCommand* cmd)
{
	bool result = false ;
	int cmdID =  cmd->m_id;
	IAttributes* attr = cmd->m_Attributes;	
	switch(cmdID)
	{		
		case CMD_ENABLEOBJ:
			result = EnableObject(attr);
		break;
		case CMD_MOVETO:
			result = MoveTo(attr);
		break;
		case CMD_PLAYTUTO:
			result = PlayTuto(attr);
			break;
		default:
			DEBUG_OUT("Unknown Command %d !!!" , cmdID);
			result = true;
		break;
	}

	return result;
}

//void CinematicThread::SetThreadInCutscene ()
//{
//	m_isInCutscene = true;
//}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
bool CinematicThread::executeCommand( SCinematicEvent* s)
{
	bool scriptEnded = s->m_CurrentStep >= s->m_CommandData.size() ;
	
	while (!scriptEnded)
	{
		CinematicCommand* cmd = s->m_CommandData[s->m_CurrentStep];
		IAttributes* attr;		
		attr = cmd->m_Attributes;
		
		//DEBUG_OUT("Executing Command %s \n" , stringc(cmd->m_Name.c_str()).c_str() );

		bool result = false ;	

		
		result = doCommand(cmd);		
		

		if (result)
		{
			s->m_CurrentStep ++;
			scriptEnded = s->m_CurrentStep >= s->m_CommandData.size() ;		
			//script ended but ip was set so we need to turn back 
			if (scriptEnded && m_InstructionPointer != -1)
			{
				s->m_CurrentStep = m_InstructionPointer;
			}
		}
		else
		{
			//if (!m_bIsTest) 
			{
				DEBUG_OUT("CCinematicThread::executeCommand some error occured in cinematic %d \n " , m_Id);
			}
			scriptEnded = true;
		}
	}	

	return true;
}

bool CinematicThread::EnableObject(IAttributes* attr)
{
	m_Obj->SetEnabled(attr->getAttributeAsBool("value"));

	return true;
}

bool CinematicThread::MoveTo(IAttributes* attr)
{
	Robot* robot = (Robot*)m_Obj;
	//robot->reset();
	//robot->SetPosition(attr->getAttributeAsInt("X"),attr->getAttributeAsInt("Y"));
	robot->SetTarget(attr->getAttributeAsFloat("TargetX"),attr->getAttributeAsFloat("TargetY"));
	return true;
}

bool CinematicThread::PlayTuto(IAttributes* attr)
{
	//GetTutorialManager()->PlayTuto(attr->getAttributeAsInt("TutoType"));
	return true;
}